package airAgent.group2;

import ontology.ontology.AirAgentOntology;
import ontology.ontology.Direction;
import ontology.ontology.InformDate;
import ontology.ontology.ReturnTicketPrice;
import ontology.ontology.Ticket;
import jade.content.Concept;
import jade.content.ContentElement;
import jade.content.lang.Codec;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.content.onto.basic.Action;
import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.CyclicBehaviour;
import jade.core.behaviours.SimpleBehaviour;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;

import java.util.Arrays;
import java.util.Comparator;
import java.util.Random;
import java.util.ArrayList;

import airAgent.group2.util.Util;

public class Client extends Agent {
	private static final long serialVersionUID = 1L;
	private Codec codec = new SLCodec();
	private boolean start;
	private Ontology ontology = AirAgentOntology.getInstance();
	private ArrayList<Ticket> ticketList = new ArrayList<Ticket>();
	private boolean priceRequested = false;
	private boolean returnPriceRequested = false;
	private boolean goingTicketBought = false;
	private Ticket goingTicket;
	private Ticket returnTicket;
	private int day;
	private double budget = Util.getRandom(Util.BUDGET, Util.BUDGET_VARIANCE);
	private int ticketseats = new Random().nextInt(5) + 1;

	private AID airline;

	protected void setup() {
		Util.register(this.getName(), Util.CLIENT, this);
		
		getContentManager().registerLanguage(codec);
		getContentManager().registerOntology(ontology);

		start = true; // false; ALID

		// SUBSCRIBE TO TIMER
		Util.addTimerBehavior(this);

		// FIND AIRLINES, ASK PRICES, BUY GOING TICKET
		addBehaviour(new SimpleBehaviour(this) {
			private static final long serialVersionUID = 1L;
			private boolean done;
			private Ticket ticket = new Ticket();
			private int numAirlines = 0;
			private int requestedTicketNum = 0;

			public void action() {
				doWait(1000);
				if (start) {
					if (!priceRequested && day != 0) {
						int flyingdate = day
						+ (int) (Math.random() * ((Util.SIMULATION_DAYS - day) + 1));
						DFAgentDescription[] res = Util.search(myAgent,
								Util.AIRLINE);
						if (res.length > 0) {
							numAirlines = res.length;
							for (int i = 0; i < res.length; i++) {
								airline = (AID) res[i].getName();
								Direction d = new Direction();
								d.setValue(true);
								ticket.setTicketDate(flyingdate);
								ticket.setTicketDirection(d);
								ticket.setTicketSeats(ticketseats);
								ticket.setTicketAirlineID(airline);
								Util.CheckTicketPrice(myAgent, airline, codec,
										ontology, ticket);
								requestedTicketNum = 1;
								priceRequested = true;

								if ((flyingdate + 1) < Util.SIMULATION_DAYS) {
									ticket.setTicketDate(flyingdate + 1);
									Util.CheckTicketPrice(myAgent, airline,
											codec, ontology, ticket);
									requestedTicketNum = 2;
								}
								if ((flyingdate + 2) < Util.SIMULATION_DAYS) {
									ticket.setTicketDate(flyingdate + 2);
									Util.CheckTicketPrice(myAgent, airline,
											codec, ontology, ticket);
									requestedTicketNum = 3;
								}

							}

						}

						else {
							doWait(5000);
						}
					}
					if (ticketList.size() >= (numAirlines * requestedTicketNum)
							&& ticketList.size() != 0) {

						goingTicket = getCheapest();
						if (budget > goingTicket.getTicketPrice().getValue()) {
							Util.BuyTicket(myAgent, airline, codec, ontology,
									goingTicket);
							budget -= goingTicket.getTicketPrice().getValue();
							ticketList.clear();
							goingTicketBought = true;
							done = true;
						} else if (day + 1 < goingTicket.getTicketDate()){
							ticketList.clear();
							priceRequested = false;
						}else 
							doDelete();
					}
				}
			}

			@Override
			public boolean done() {
				return done;
			}
		});

		// FIND AIRLINES, ASK PRICES, BUY RETURN TICKET
		addBehaviour(new SimpleBehaviour(this) {
			private static final long serialVersionUID = 1L;
			private boolean done;
			private Ticket ticket = new Ticket();
			private int numAirlines = 0;

			public void action() {
				if (goingTicketBought) {
					if (!returnPriceRequested) {
						DFAgentDescription[] res = Util.search(myAgent,
								Util.AIRLINE);
						if (res.length > 0) {
							numAirlines = res.length;
							for (int i = 0; i < res.length; i++) {
								airline = (AID) res[i].getName();
								Direction d = new Direction();
								d.setValue(false);
								if (goingTicket.getTicketDate() + 3 > Util.SIMULATION_DAYS)
									ticket.setTicketDate(Util.SIMULATION_DAYS);
								else
									ticket.setTicketDate(goingTicket
											.getTicketDate() + 3);
								ticket.setTicketDirection(d);
								ticket.setTicketSeats(ticketseats);
								ticket.setTicketAirlineID(airline);
								Util.CheckTicketPrice(myAgent, airline, codec,
										ontology, ticket);

								returnPriceRequested = true;
							}

						}

						else {
							doWait(5000);
						}
					}
					if (ticketList.size() >= numAirlines /* Util.NumAirlines */
							&& ticketList.size() != 0) {
						returnTicket = getCheapest();
						if (returnTicket.getTicketPrice().getValue() > budget)
							Util.CancelTicket(myAgent, airline, codec,
									ontology, goingTicket);
						else
							Util.BuyTicket(myAgent, airline, codec, ontology,
									returnTicket);
						if (new Random().nextInt(100) + 1 < Util.CANCELLATION_RATE) {
							Util.CancelTicket(myAgent, airline, codec,
									ontology, goingTicket);
							Util.CancelTicket(myAgent, airline, codec,
									ontology, returnTicket);
						}
						doDelete();
						done = true;
					}
				}
			}

			@Override
			public boolean done() {
				return done;
			}
		});

		addBehaviour(new CyclicBehaviour(this) {
			private static final long serialVersionUID = 1L;

			public void action() {
				ACLMessage msg = receive(MessageTemplate.MatchAll());
				if (msg != null) {
					ContentElement ce = null;
					if (msg.getPerformative() == ACLMessage.INFORM) {
						if (msg.getProtocol().equals(
								AirAgentOntology.RETURNTICKETPRICE)) {
							try {
								ce = getContentManager().extractContent(msg);
							} catch (Exception e) {
								e.printStackTrace();
							}
							Ticket ticket = new Ticket();
							if (ce instanceof Action) {
								Action agAction = (Action) ce;
								Concept con = agAction.getAction();
								if (con instanceof ReturnTicketPrice) {

									ticket.setTicketPrice(((ReturnTicketPrice) con)
											.getPrice().getTicketPrice());
									ticket.setTicketDirection(((ReturnTicketPrice) con)
											.getPrice().getTicketDirection());
									ticket.setTicketAirlineID(msg.getSender());
									ticket.setTicketDate(((ReturnTicketPrice) con)
											.getPrice().getTicketDate());
									ticket.setTicketSeats(((ReturnTicketPrice) con)
											.getPrice().getTicketSeats());
									ticket.setTicketClientID(myAgent.getAID());
									ticketList.add(ticket);
								}
							}
						} else if (msg.getProtocol().equals(
								AirAgentOntology.BUYTICKET)) {
							goingTicketBought = true;
						} /*else if (msg.getProtocol().equals(
								AirAgentOntology.CANCELTICKET))
							System.out.println("Ticket is canceled");*/
						else if (msg.getProtocol().equals(
								AirAgentOntology.INFORMDATE)) {
							try {
								ce = getContentManager().extractContent(msg);
							} catch (Exception e) {
								e.printStackTrace();
							}
							if (ce instanceof Action) {
								Action agAction = (Action) ce;
								Concept con = agAction.getAction();
								if (con instanceof InformDate) {
									day = ((InformDate) con).getDate();
								}
							}
						} else if (msg.getProtocol().equals(
								AirAgentOntology.STARTSIMULATION)) {
							start = true;
						} else if (msg.getProtocol().equals(
								AirAgentOntology.ENDOFSIMULATION)) {
						} 
						// }
					} /*else if (msg.getPerformative() == ACLMessage.REFUSE) {
						if (msg.getProtocol() == AirAgentOntology.BUYTICKET)
							System.out.println(myAgent.getLocalName()
									+ ": The ticket buying is refused");
						else if (msg.getProtocol() == AirAgentOntology.CANCELTICKET)
							System.out.println(myAgent.getLocalName()
									+ " couldnt cancel the ticket");
						else if (msg.getProtocol() == AirAgentOntology.RETURNTICKETPRICE)
							System.out.println(myAgent.getLocalName()
									+ ": Return ticket price refused");
					} else if (msg.getPerformative() == ACLMessage.AGREE) {
						// System.out.println(myAgent.getLocalName() +
						// " succesfully subscribed");
						;
					}*/
				}

			}
		});

	}

	private Ticket getCheapest() {
		Ticket[] t = new Ticket[ticketList.size()];
		ticketList.toArray(t);
		Arrays.sort(t, new Comparator<Ticket>() {
			@Override
			public int compare(ontology.ontology.Ticket arg0,
					ontology.ontology.Ticket arg1) {
				return (int) (arg0.getTicketPrice().getValue() - arg1
						.getTicketPrice().getValue());
			}
		});
		return t[0];
	}

}
